#ifndef GRAPHS_H_
#define GRAPHS_H_

class Matrix;
class PartialOrder;
namespace SAT
{
	class Var;
	class SAT;
}
#include <set>
#include <vector>

namespace Graphs
{
	
	/** 
	 * @brief 
	 * 
	 * @param m input
	 * @param epsilon input
	 * @param X input
	 * @param X_m output (X-)
	 * @param X_p output (X+)
	 * @param order_m output (<=-)
	 * @param order_p output (<=+)
	 * 
	 * @return 
	 */
bool partitionAndSort(Matrix *m, double epsilon, unsigned int leftBoundHole1, unsigned int rightBoundHole1, 
		unsigned int leftBoundHole2, unsigned int rightBoundHole2, std::set<unsigned int> &Xij, 
		std::vector<std::set<unsigned int> > &cellsOfOL, std::set<unsigned int> &X_m, 
		std::set<unsigned int> &X_p, std::vector<PartialOrder*> &Cij_m, 
		std::vector<PartialOrder*> &Cij_p, std::vector<unsigned int> &cellsOrder_m, 
		std::vector<unsigned int> &cellsOrder_p);
    
    void graphS(std::vector<std::set<unsigned int> > &S, std::vector<unsigned int> &X, 
        	std::vector<double> &d, double epsilon, Matrix *m);
   
    void graphL(std::vector<std::set<unsigned int> > &L, std::vector<unsigned int> &X, 
    		std::vector<double> &d, double epsilon,Matrix *m);
    
    void partitionL(std::vector<unsigned int> &blockOfL, std::vector<std::set<unsigned int> > &L);
   
    void graphOL(std::vector<std::set<unsigned int> > &OL, std::vector<unsigned int> &X, 
            std::vector<unsigned int> &blockOfL, std::vector<std::set<unsigned int> > &L, 
            std::vector<double> &d, double epsilon, Matrix *m );
    
    void cellsOL(std::vector<std::set<unsigned int> > &L, std::vector<std::set<unsigned int> > &OL,
            std::vector<std::set<unsigned int> > &cellsOfOL, std::vector<unsigned int> &xCellsOfOl );
    
    void graphPsy(std::vector<std::set<unsigned int> > &psy, std::vector<std::set<unsigned int> > &cellsOfOL, 
       		std::vector<unsigned int> xCellsOfOl, std::vector<unsigned int> &blockOfL, 
       		std::vector<std::set<unsigned int> > &S, std::vector<std::set<unsigned int> > &L, 
            std::vector<unsigned int> &X, std::vector<double> &d, double epsilon, Matrix *m );
    
    bool sat( std::vector< SAT::Var > &vVar, std::vector<std::set<unsigned int> > &Gij, std::vector<std::set<unsigned int> > &G1, std::vector<std::set<unsigned int> > &G2, 
            std::vector<std::set<unsigned int> > &G3, std::vector<std::set<unsigned int> > &cellsOfOL,
            std::vector<unsigned int> &clusterOfPsy, std::vector<std::set<unsigned int> > &clusters, 
            std::vector<unsigned int> &X, std::vector<std::set<unsigned int> > &L, 
            std::vector<double> &d, double epsilon, Matrix *m, unsigned int leftBoundHole1,
            unsigned int rightBoundHole1, unsigned int leftBoundHole2, unsigned int rightBoundHole2);
    
    bool isG2(unsigned int i, unsigned int j, std::vector<std::set<unsigned int> > &cellsOfOL, 
    		std::vector<double> &d, double epsilon);
    
    bool isG3(unsigned int i, unsigned int j, std::vector<std::set<unsigned int> > &cellsOfOL,
    		std::vector<double> &d, double epsilon, std::vector<unsigned int> &X, 
    		std::vector<std::set<unsigned int> > &L, Matrix *m);
    
    void createOmega( std::set< std::pair<unsigned int, unsigned int> > &omega, std::vector<std::set<unsigned int> > &G1,
    		std::vector<std::set<unsigned int> > &G2, std::vector<std::set<unsigned int> > &G3 );
    
    void partition(std::set<unsigned int> &X_m, std::set<unsigned int> &X_p, std::vector<std::set<unsigned int> > &Gij,
    		std::vector<PartialOrder* > &Cij_m, std::vector<PartialOrder* > &Cij_p, unsigned int leftBoundHole1,
    		unsigned int rightBoundHole1, unsigned int leftBoundHole2, unsigned int rightBoundHole2, 
    		std::vector< SAT::Var > &vVar, std::vector<unsigned int> &cellsOrder_m,
    		std::vector<unsigned int> &cellsOrder_p, std::vector<std::set<unsigned int> > &cellsOfOL,
    		std::vector<unsigned int> &X, std::vector<std::set<unsigned int> > &L, 
    		std::vector<double> &d, double epsilon, Matrix *m );
   
    bool aarrow(unsigned int i, unsigned int j, double epsilon, std::vector<double> &d, 
    		std::vector<unsigned int> &X, std::vector<std::set<unsigned int> > &L, Matrix *m);
   
    bool twinClusters( std::vector<unsigned int > &clusterOfPsy, unsigned int a, unsigned int b );
   
    void calculateDx(std::vector<double> &d, std::vector<unsigned int> &X, Matrix *m);

};

#endif /*GRAPHS_H_*/
